home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Shareware Grab Bag
/
Shareware Grab Bag.iso
/
090
/
hppcmode.arc
/
KBIBM.ASM
next >
Wrap
Assembly Source File
|
1984-10-08
|
50KB
|
1,321 lines
page 60,132
;****************************************************************************
;****************************************************************************
;
; KBIBM.ASM -
; IBM STYLE KEYBOARD DRIVER FOR THE HP150
;
; Kirk L. Bentson
;
; Hewlett-Packard
; Personal Office COmputer Division
; March 1984
;
; Modification History -
;
; Code taken over Aug, 1984 by Frank Heartney. All separate
; Include files combined into a single source file, code and
; data included in a segment called 'CODE'. Calling sequences
; changed to be used with PC.ASM, a PC emulator on the HP150.
;
;
; these routines take over keyboard handling at the hardware level.
; When these routines are active, the HP150 firmware is getting
; no reports from the keyboard, and the keyboard returns it's
; information in IBM PC style format.
;
;****************************************************************************
;****************************************************************************
;****************************************************************************
; Keyboard driver constant equates.
;****************************************************************************
TRUE equ 001H ;Non-zero boolean true value
FALSE equ 000H ;Zero boolean false value
SUCCESS equ 001H ;Non-zero boolean success value
FAIL equ 000H ;Zero boolean fail value
KBSW_TYPE equ 016H ;Keyboard I/O interrupt number
BREAK_TYPE equ 01BH ;User break routine interrupt
KBHW_TYPE equ 043H ;8041 interrupt number
KB_STAT equ 019H ;8041 status port - read
KB_CMND equ 019H ;8041 command port - write
KB_DATA equ 018H ;8041 data port - read
IC_CMND equ 010H ;8259 command port - write
ACK_CMND equ 010H ;8041 Acknowledge interrupt command
TONE_0_CMND equ 030H ;8041 Generate tone 030H command
EOI_CMND equ 020H ;8259 End Of Interrupt command
;8041 status register bit masks
;Note - Bits 4,5,6,7 have different meanings depending on last 8041 function
; Only keyboard and touchscreen masks have been defined here
OBF_MASK equ 00000001B ;8041 status, OBF flag mask
IBF_MASK equ 00000010B ;8041 status, IBF flag mask
REL_MASK equ 00110000B ;8041 status, touch release mask
ROW_MASK equ 01000000B ;8041 status, touch report row mask
COL_MASK equ 01010000B ;8041 status, touch report col mask
TS_MASK equ REL_MASK or ROW_MASK or COL_MASK
KEY_RELEASE equ 10000000B ;8041 data, key released mask
;****************************************************************************
;****************************************************************************
;
; KBDRIVER.ASM -
; KEYBOARD DRIVER INIT, RESET, AND 8041 COMMUNICATION ROUTINES
;
;
; The routines in this module perform the functions needed to initialize
; the keyboard driver at start-up and to reset the system state when
; the driver is no longer needed. All necessary routines are provided
; for communicating with the 8041.
; kb_init - Initialize keyboard driver
; kb_reset - Reset system state
; kb_cmnd_out - Send command to 8041
;****************************************************************************
;****************************************************************************
seg_0 segment at 00000H
assume cs:nothing,ds:nothing,ss:nothing,es:nothing
org KBSW_TYPE*4
kb_io_ptr label dword ;Keyboard I/O interrupt vector
kb_io_oset label word ; Offset
org kb_io_oset+2
kb_io_seg label word ; Segment
org BREAK_TYPE*4
break_ptr label dword ;User break routine interrupt
break_oset label word ; Offset
org break_oset+2
break_seg label word ; Segment
org KBHW_TYPE*4
kb_int_ptr label dword ;8041 interrupt vector
kb_int_oset label word ; Offset
org kb_int_oset+2
kb_int_seg label word ; Segment
seg_0 ends
page
pccode segment byte public 'CODE'
assume cs:pccode,ds:pccode
;The keyboard driver is installed by setting all necessary interrupt vectors
;to point to the proper driver routines. Before the interrupt vectors are
;changed they are saved so that they may be restored to remove the keyboard
;driver and return the system to its normal keyboard state.
;These save areas are set up to store the original interrupt vectors.
kbsw_save label dword ;Keyboard I/O vector save area
kbsw_oset dw ? ; Offset
kbsw_seg dw ? ; Segment
;****************************************************************************
; KB_INIT - Initialize keyboard driver.
; This routine installs and initializes the keyboard driver. The
; keyboard driver is installed by saving the necessary interrupt
; vectors and replacing them with new vectors that point to
; the keyboard driver's routines.
;
; Registers in:
; None.
; Registers out:
; None.
; Registers preserved:
; All.
;****************************************************************************
public kb_init
kb_init proc near ;Initialize keyboard routines
push ax ;Save callers registers
push ds
push es
push cs ;data is in code segment.
pop ds
sub ax,ax ;Point es to segment 0
mov es,ax
cli ;Disable external interrupts
mov ax,es:kb_io_oset ;Save current keyboard I/O vector
mov kbsw_oset,ax
mov ax,es:kb_io_seg
mov kbsw_seg,ax
mov ax,offset kb_io ;Install new keyboard I/O vector
mov es:kb_io_oset,ax
mov es:kb_io_seg,cs
sti ;Enable external interrupts
pop es ;Restore callers registers
pop ds
pop ax
ret ;Return to caller
kb_init endp
page
;****************************************************************************
; KB_RESET - Remove keyboard driver and return system to normal keyboard.
; This routine removes the keyboard driver by restoring the
; necessary interrupt vectors with the values that were stored
; when the driver was initialized.
;
; Registers in:
; None.
; Registers out:
; None.
; Registers preserved:
; All.
;****************************************************************************
public kb_reset
kb_reset proc near ;Reset keyboard routines
push ax ;Save callers registers
push ds
push es
push cs ;data is in code segment.
pop ds
sub ax,ax ;Point es to segment 0
mov es,ax
cli ;Disable external interrupts
mov ax,kbsw_oset ;Restore keyboard I/O vector
mov es:kb_io_oset,ax
mov ax,kbsw_seg
mov es:kb_io_seg,ax
sti ;Enable external interrupts
pop es ;Restore callers registers
pop ds
pop ax
ret ;Return to caller
kb_reset endp
page
;****************************************************************************
; KB_CMND_OUT - Send a command to the 8041
; This routine checks to see if the 8041 is ready for a command.
; If it is then the specified command byte is written to the 8041.
; If the 8041 is busy then this routine waits for awhile to see if
; it becomes ready.
;
; Registers in:
; AH - Command byte to be sent to 8041
; Registers out:
; AX - 00001H if the command was sent to the 8041
; 00000H - timeout, 8041 is busy
; Registers preserved:
; All except AX.
;****************************************************************************
kb_cmnd_out proc near
push cx ;Save callers cx
mov cx,0FFFFH
kb_cmnd_01 label near
in al,KB_STAT ;Read 8041 status byte
test al,IBF_MASK ;If IBF=1 then loop for awhile to
jz kb_cmnd_02 ; see if it changes to 0
loop kb_cmnd_01
mov ax,FAIL ;Timeout - set return value and
jmp kb_cmnd_03 ; return
kb_cmnd_02 label near
mov al,ah ;Write command to 8041
out KB_CMND,al
mov ax,SUCCESS ;Set return value
kb_cmnd_03 label near
pop cx ;Restore callers cx
ret ; and return to caller
kb_cmnd_out endp
;****************************************************************************
;****************************************************************************
;
; KEYBOARD QUEUE HANDLING ROUTINES
;
;
; Each routine in this module performs a function related to keyboard
; queue management. The keyboard queue is a fixed length FIFO queue
; whose entries are two bytes (one word) in length. The queue entries
; are stored in a contiguous memory area the length of which is
; determined by a constant equate. The first word of the memory area is
; referred to as the queue beginning and the last word is referred to as
; the queue end. The oldest entry placed in the queue is referred to as
; the head entry and the latest queue entry is referred to as the tail
; entry. A keyboard queue pointer is a segment offset to an entry in
; the queue. Every keyboard pointer must point to an address within the
; queue memory area at all times.
; kb_inc_ptr - Increment keyboard queue pointer by one entry
; kb_is_q_empty - Returns ZF=1 if keyboard queue is empty
; kb_is_q_full - Returns ZF=1 if keyboard queue is full
; kb_reset_q - Resets keyboard queue to empty
; kb_read_q - If keyboard queue not empty
; returns head queue entry
; kb_write_q - If keyboard queue not full
; adds ax to queue tail
;****************************************************************************
;****************************************************************************
page
KB_QUEUE_LEN equ 051 ;Keyboard queue length in words
kb_queue dw KB_QUEUE_LEN dup(?) ;Keyboard queue
kb_q_end label word ; End of queue pointer
kb_q_head dw offset kb_queue ; Keyboard queue head pointer
kb_q_tail dw offset kb_queue ; Keyboard queue tail pointer
;****************************************************************************
; KB_INC_PTR - Increment keyboard queue pointer by one entry.
; The keyboard queue pointer in bx is incremented by one word and
; if it then points past the end of the queue the pointer is
; wrapped around to the beginning of the queue.
;
; Registers in:
; BX - Keyboard queue pointer
; Registers out:
; BX - Incremented keyboard queue pointer
; Registers preserved:
; All except BX, FF
;****************************************************************************
kb_inc_ptr proc near ;Increment keyboard queue pointer
add bx,2 ;Point to next queue entry
cmp bx,offset kb_q_end ;If at end of queue
jb kb_inc_005 ; then wrap around to beginning
mov bx,offset kb_queue ; of queue
kb_inc_005 label near
ret ;Return to caller
kb_inc_ptr endp
;****************************************************************************
; KB_IS_Q_EMPTY - Check if keyboard queue is empty.
; This routine sets the zero flag (ZF) to reflect whether the
; keyboard queue is empty or not.
;
; Registers in:
; None.
; Registers out:
; FF - ZF=1 - Keyboard queue is empty
; ZF=0 - Keyboard queue is not empty
; Registers preserved:
; All except FF
;****************************************************************************
public kb_is_q_empty
kb_is_q_empty proc near ;Returns ZF=1 if keyboard queue
push bx ; is empty
mov bx,kb_q_tail
cmp bx,kb_q_head ;Set ZF to reflect queue status
pop bx
ret ;Return to caller
kb_is_q_empty endp
page
;****************************************************************************
; KB_IS_Q_FULL - Check if keyboard queue is full.
; This routine sets the zero flag (ZF) to reflect whether the
; keyboard queue is full or not.
;
; Registers in:
; None.
; Registers out:
; FF - ZF=1 - Keyboard queue is full
; ZF=0 - Keyboard queue is not full
; Registers preserved:
; All except FF
;****************************************************************************
kb_is_q_full proc near ;Returns ZF=1 if keyboard queue
push bx ; is full
mov bx,kb_q_tail
call kb_inc_ptr
cmp bx,kb_q_head ;Set ZF to reflect queue status
pop bx
ret ;Return to caller
kb_is_q_full endp
;****************************************************************************
; KB_RESET_Q - Resets the keyboard queue to empty.
; This routine simply sets the keyboard queue head and tail pointers
; to the queue beginning thereby setting the queue to an empty state.
;
; Registers in:
; None.
; Registers out:
; None.
; Registers preserved:
; All except FF
;****************************************************************************
kb_reset_q proc near ;Resets keyboard queue to empty
push bx
mov bx,offset kb_queue
mov kb_q_head,bx
mov kb_q_tail,bx
pop bx
ret ;Return to caller
kb_reset_q endp
page
;****************************************************************************
; KB_READ_Q - Read the head keyboard queue entry.
; If the keyboard queue is not empty this routine reads the head
; entry and removes it from the queue.
;
; Registers in:
; None.
; Registers out:
; FF - ZF=0 - Operation successful
; AX contains head keyboard queue entry
; ZF=1 - Operation unsuccessful
; Keyboard queue was empty
; Registers preserved:
; All except AX, FF
;****************************************************************************
kb_read_q proc near ;If keyboard queue not empty
push bx ; returns ZF=0 and head queue
call kb_is_q_empty ; element in AX
jz kb_read_005 ;else
mov bx,kb_q_head ; returns ZF=1
mov ax,[bx]
call kb_inc_ptr
mov kb_q_head,bx
or bh,0ffh ;Reset ZF, operation successful
kb_read_005 label near
pop bx
ret ;Return to caller
kb_read_q endp
page
;****************************************************************************
; KB_WRITE_Q - Add AX to keyboard queue.
; If the keyboard queue is not full this routine adds the value in
; AX to the tail of the queue.
;
; Registers in:
; AX - Keyboard queue entry to be added
; Registers out:
; FF - ZF=0 - Operation successful
; ZF=1 - Operation unsuccessful
; Keyboard queue was full
; Registers preserved:
; All except FF
;****************************************************************************
kb_write_q proc near ;If keyboard queue not full
push bx ; adds AX to queue tail and
call kb_is_q_full ; returns ZF=0
jz kb_write_005 ;else
mov bx,kb_q_tail ; returns ZF=1
mov [bx],ax
call kb_inc_ptr
mov kb_q_tail,bx
or bh,0ffh ;Reset ZF, operation successful
kb_write_005 label near
pop bx
ret ;Return to caller
kb_write_q endp
;****************************************************************************
;****************************************************************************
;
; IBM PC KEYBOARD INTERRUPT EMULATION ROUTINES
;
;
; Each routine in this module is an interrupt service routine that
; emulates the function performed by the corresponding service routine
; in the IBM PC. The service routines in this module support the IBM
; PC keyboard functions.
; ibm_io - INT 016H, IBM keyboard I/O service routine
; ibm_break - INT 01BH, IBM dummy user break service routine
; ibm_int - INT 043H, (IBM INT 009H) IBM keyboard interrupt
;****************************************************************************
;****************************************************************************
;IBM keyboard flag byte kb_flag (kb_flag_msb) bit equates
INS_MODE equ 10000000B ;Insert mode mask
CAPS_MODE equ 01000000B ;Caps lock mode mask
NUM_MODE equ 00100000B ;Numeric lock mode mask
SCROLL_MODE equ 00010000B ;Scroll lock mode mask
EXT_SHIFT equ 00001000B ;Extended character key down mask
CTRL_SHIFT equ 00000100B ;Control key down mask
LEFT_SHIFT equ 00000010B ;Left shift key down mask
RIGHT_SHIFT equ 00000001B ;Right shift key down mask
;IBM keyboard flag byte kb_flag_1 (kb_flag_lsb) bit equates
INS_SHIFT equ 10000000B ;Insert key down mask
CAPS_SHIFT equ 01000000B ;Caps lock key down mask
NUM_SHIFT equ 00100000B ;Numeric lock key down mask
SCROLL_SHIFT equ 00010000B ;Scroll lock key down mask
HOLD_MODE equ 00001000B ;Suspend mode mask
; equ 00000100B ;Unused
; equ 00000010B ;Unused
; equ 00000001B ;Unused
;Interrupt type 016H keyboard I/O service function equates
IBM_FCN_00 equ 000H ;IBM function code 000
IBM_FCN_01 equ 001H ;IBM function code 001
IBM_FCN_02 equ 002H ;IBM function code 002
HP_FCN_CODE equ 10000000B ;HP function code mask
HP_FCN_00 equ 080H ;HP function code 000
HP_FCN_01 equ 081H ;HP function code 001
HP_FCN_02 equ 082H ;HP function code 002
HP_FCN_03 equ 083H ;HP function code 003
HP_FCN_04 equ 084H ;HP function code 004
HP_FCN_05 equ 085H ;HP function code 005
;HP ITF keyboard key position equates.
NUM_KEY equ 088 ;HP-150 key 088
SCROLL_KEY equ 089 ;HP-150 key 089
LEXT_KEY equ 080 ;HP-150 key 080
REXT_KEY equ 082 ;HP-150 key 082
CTRL_KEY equ 048 ;HP-150 key 048
CAPS_KEY equ 047 ;HP-150 key 047
LSHFT_KEY equ 064 ;HP-150 key 064
RSHFT_KEY equ 075 ;HP-150 key 075
INS_KEY equ 029 ;HP-150 key 029
BREAK_KEY equ 001 ;HP-150 key 001
STOP_KEY equ 002 ;HP-150 key 002
NPAD_0_KEY equ 105 ;HP-150 key 105
NPAD_1_KEY equ 102 ;HP-150 key 102
NPAD_2_KEY equ 103 ;HP-150 key 103
NPAD_3_KEY equ 104 ;HP-150 key 104
NPAD_4_KEY equ 098 ;HP-150 key 098
NPAD_5_KEY equ 099 ;HP-150 key 099
NPAD_6_KEY equ 100 ;HP-150 key 100
NPAD_7_KEY equ 094 ;HP-150 key 094
NPAD_8_KEY equ 095 ;HP-150 key 095
NPAD_9_KEY equ 096 ;HP-150 key 096
;These equates provide the proper displacement into a keycode mapping table
;entry depending on the current shift mode.
BASE_INDEX equ 000 ;Keycode table entry index
SHIFT_INDEX equ 002 ;Keycode table entry index
CTRL_INDEX equ 004 ;Keycode table entry index
EXTC_INDEX equ 006 ;Keycode table entry index
page
;The keyboard driver is installed by setting all necessary interrupt vectors
;to point to the proper driver routines. Before the interrupt vectors are
;changed they are saved so that they may be restored to remove the keyboard
;driver and return the system to its normal keyboard state.
;These save areas are set up to store the original interrupt vectors.
brk_save label dword ;User break routine vector save
brk_oset dw ? ; Offset
brk_seg dw ? ; Segment
kbhw_save label dword ;8041 interrupt vector save area
kbhw_oset dw ? ; Offset
kbhw_seg dw ? ; Segment
;The keyboard interrupt service routine uses its own local stack. The
;interrupt routine must be reentrant because of the PAUSE function. Therefore,
;the interrupted routine's stack pointer is temporarily saved in the area
;defined here, the local stack is allocated from the stack space defined here,
;and the saved stack pointer is pushed onto the local stack.
old_stack label dword ;Interrupted routine's stack ptr
old_sp dw 0 ; Saved SP
old_ss dw 0 ; Saved SS
new_stack label word ;kb_int local stack
dw 128 dup(?) ; 128 word stack
new_top label word ; Local stack top pointer
new_sp dw new_top ;Top of stack pointer
STACK_LEN equ (new_top-new_stack)/2 ;Allocated stack length
;The keycode translation table is used to translate a key position number to
;a two byte keycode. A pointer to the table is stored here so that an
;application may supply its own table to remap keys as needed.
kb_kc_table label dword ;Keycode translation table pointer
kb_kc_oset dw offset ibm_table ; Offset
kb_kc_seg dw seg ibm_table ; Segment
;The flag bytes reflect the current state of the shift keys and the state
;of toggle modes. These flags correspond to the IBM PC keyboard flag bytes as
;follows:
; kb_flag_msb ~ kb_flag
; kb_flag_lsb ~ kb_flag_1
kb_flag label word ;Keyboard flags
kb_flag_msb db 00000000B ; Keyboard flags MSB
kb_flag_lsb db 00000000B ; Keyboard flags LSB
;The touchscreen touch coordinates are reported in these bytes. Note that
;touch reports are not buffered in any way - if the screen is being touched
;these bytes contain the coordinates of the touch. These bytes are set to
;0FFFFH whenever the screen is not being touched.
ts_row_col label word ;Touchscreen touch coordinates
ts_row db 0FFH ; Touch row
ts_col db 0FFH ; Touch column
;The 8041 reports two bytes for each screen touch - the first is the row
;coordinate and the second is the column coordinate. The touch coordinates
;are not reported by the interrupt service routine until both have been read
;from the 8041. Therefore, the row coordinate must be saved until the column
;coordinate is read. The 8041 also reports a single byte when the touchscreen
;is released.
ts_save db 0FFH ;Temp save area for row coordinate
;The IBM PC keyboard alt-numeric pad special function is emulated. The user
;can enter any character code (0-255) by pressing Extend char and typing the
;decimal value of a character code on the numeric pad keys. Actually the
;range is (1-255) as in the IBM PC implementation. This byte (ext_data)
;corresponds to the (alt_input) IBM PC keyboard byte.
ext_data db 000 ;Extend char data value
kb_shift label byte ;Table of shift keys
db INS_KEY ;Any key entered in this table
db CAPS_KEY ; will be trapped in the
db NUM_KEY ; keyboard interrupt service
db SCROLL_KEY ; routine as a shift key. Note
db LEXT_KEY ; that there is a one to one
db REXT_KEY ; mapping from the entries in
db CTRL_KEY ; this table to the entries in
db LSHFT_KEY ; the following table kb_mask
db RSHFT_KEY ; This table corresponds to the
KB_SHIFT_LEN equ $-kb_shift ; IBM PC keyboard table K6.
kb_mask label byte ;Shift mask table
db INS_SHIFT ;The entries in this table are the
db CAPS_SHIFT ; bit masks for the keyboard flag
db NUM_SHIFT ; bytes corresponding to the
db SCROLL_SHIFT ; shift keys in kb_shift.
db EXT_SHIFT ; This table corresponds to the
db EXT_SHIFT ; IBM PC keyboard table K7.
db CTRL_SHIFT
db LEFT_SHIFT
db RIGHT_SHIFT
num_pad_keys label word ;Numeric pad key table
db NPAD_0_KEY ;This is a table of the HP ITF
db NPAD_1_KEY ; keyboard numeric pad keys.
db NPAD_2_KEY ; Sequence is important here
db NPAD_3_KEY ; because the displacement in
db NPAD_4_KEY ; bytes from the beginning of the
db NPAD_5_KEY ; table to any entry gives the
db NPAD_6_KEY ; numeric value of the key.
db NPAD_7_KEY ; This table corresponds to the
db NPAD_8_KEY ; IBM PC keyboard table K30.
db NPAD_9_KEY
NUM_PAD_LEN equ $-num_pad_keys
page
;****************************************************************************
; IBM_IO - Interrupt type 016H service routine.
; Software interrupt - keyboard I/O service
; This routine provides keyboard I/O service for an application
; program. Depending on the function code this routine can return
; the current keyboard flags, queue status, next queue entry, or
; touchscreen touch coordinates.
;
; Registers in:
; AH - Function code:
; 000H - IBM function code 00
; Read the next key pressed and return the
; ascii code in AL and the extended code in
; AH
; 001H - IBM function code 01
; Return the keyboard queue status in ZF:
; ZF=1 - Keyboard queue is empty
; ZF=0 - Keyboard queue is not empty
; The first key in the queue is
; returned in AX and is left in the
; queue
; 002H - IBM function code 02
; Returns the current keyboard flags in AL
; 080H - HP function code 00
; Set keyboard keycode translation routine
; to use a translation table supplied by
; the application.
; ES:DX must contain pointer to table.
; 081H - HP function code 01
; Returns the touchscreen touch cooordinates
; in AX. AH contains the row and AL contains
; the column coordinate. The coordinates are
; equal to 0FFH if no touch is available
; 082H - HP function code 02
; Flushes all data from the keyboard queue.
; 083H - HP function code 03
; Starts this keyboard driver functioning by
; altering the proper interrupt vectors
; 084H - HP function code 04
; Stops this keyboard driver by restoring
; the interrupt vectors to the original
; firmware pointers
; 085H - HP function code 05
; Returns in ES:DX a pointer to the current
; keycode translation table
; Registers out:
; See each function code under Registers in.
; Registers preserved:
; All registers are preserved except AX and:
; function code 001H - FF destroyed
; function code 085H - ES, DX destroyed
;****************************************************************************
ibm_io label far ;External label for IBM keyboard
kb_io proc far ; I/O interrupt service
sti ;Enable external interrupts
push bx ;Save callers registers
push ds
push es
push cs ;Point ds to data segment
pop ds
sub bx,bx ;Point es to segment 0
mov es,bx
page
test ah,HP_FCN_CODE ;Jump if this is an HP function
jnz kb_io_024
cmp ah,IBM_FCN_00 ;IBM function 00 - Read keyboard
jz kb_io_005 ; queue
cmp ah,IBM_FCN_01 ;IBM function 01 - Read keyboard
jz kb_io_015 ; queue status
cmp ah,IBM_FCN_02 ;IBM function 02 - Read keyboard
jz kb_io_020 ; flags
jmp kb_io_900 ;Invalid function code
kb_io_005 label near ;Read key from keyboard queue
cli
call kb_read_q ;If queue is empty then wait until
jnz kb_io_010 ; a key is pressed
sti ;Enable external interrupts and
nop ; allow an interrupt to occur
jmp kb_io_005 ; and see if a key was pressed
kb_io_010 label near ;Return the key in AX
jmp kb_io_900 ; AL-Ascii, AH-Extended code
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; NOTE - This function call does not return through kb_io_900. Be
; careful with the stack and returns.
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
kb_io_015 label near ;Read keyboard queue status
cli
mov bx,kb_q_head ;Read head queue entry without
mov ax,[bx] ; removing it from queue
call kb_is_q_empty ;Set ZF to reflect queue status,
pop es ; restore callers registers,
pop ds ; throw away saved flags,
pop bx ; enable external interrupts,
sti ; and return to caller
ret 2
kb_io_020 label near ;Read keyboard flags
mov al,kb_flag_msb ;Return keyboard flag byte in AL
jmp kb_io_900
page
kb_io_024 label near ;HP keyboard functions
cmp ah,HP_FCN_00 ;HP function 00 - Set keycode
jz kb_io_025 ; translate table pointer
cmp ah,HP_FCN_01 ;HP function 01 - Read touchscreen
jz kb_io_030 ; touch coordinates
cmp ah,HP_FCN_02 ;HP function 02 - Flush keyboard
jz kb_io_035 ; queue
cmp ah,HP_FCN_03 ;HP function 03 - Start keyboard
jz kb_io_040 ; driver
cmp ah,HP_FCN_04 ;HP function 04 - Stop keyboard
jz kb_io_045 ; driver
cmp ah,HP_FCN_05 ;HP function 05 - Read keycode
jz kb_io_050 ; translate table pointer
jmp kb_io_900
kb_io_025 label near ;Set keycode translate table ptr
cli ;Store user keycode translate table
mov kb_kc_oset,dx ; pointer for interrupt service
mov kb_kc_seg,es ; routine
jmp kb_io_900
kb_io_030 label near ;Read touch coordinates
mov ax,ts_row_col ; Get touch coordinates in AX
jmp kb_io_900 ; AH - row, AL - column
kb_io_035 label near ;Flush keyboard queue
cli ;Disable external interrupts
call kb_reset_q ;Flush queue
jmp kb_io_900
kb_io_040 label near ;Start keyboard driver
cli
mov ax,es:break_oset ;Save current user break vector
mov brk_oset,ax
mov ax,es:break_seg
mov brk_seg,ax
mov ax,es:kb_int_oset ;Save current 8041 interrupt vector
mov kbhw_oset,ax
mov ax,es:kb_int_seg
mov kbhw_seg,ax
mov ax,offset ibm_break ;Install new user break vector
mov es:break_oset,ax
mov es:break_seg,cs
mov ax,offset ibm_int ;Install new 8041 interrupt vector
mov es:kb_int_oset,ax
mov es:kb_int_seg,cs
jmp kb_io_900
kb_io_045 label near ;Stop keyboard driver
cli
mov ax,brk_oset ;Restore user break vector
mov es:break_oset,ax
mov ax,brk_seg
mov es:break_seg,ax
mov ax,kbhw_oset ;Restore 8041 interrupt vector
mov es:kb_int_oset,ax
mov ax,kbhw_seg
mov es:kb_int_seg,ax
jmp kb_io_900
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
; NOTE - This function call does not return through kb_io_900. Be
; careful with the stack and returns.
;!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
kb_io_050 label near ;Read keycode translate table ptr
cli ;Load pointer to current keycode
les dx,kb_kc_table ; translate table
pop ds ;Throw away callers es register
pop ds ;Restore remaining registers
pop bx
iret ;Return to caller
kb_io_900 label near
pop es ;Restore callers registers
pop ds ; and return to caller
pop bx
iret
kb_io endp
page
;****************************************************************************
; IBM_BREAK - Interrupt type 01BH service routine.
; Software interrupt - user break routine
; This is a dummy user break routine. At initialization the
; user break interrupt vector is set to this routine.
;
; Registers in:
; None.
; Registers out:
; None.
; Registers preserved:
; All.
;****************************************************************************
ibm_break label far ;External label for dummy user
kb_break proc far ; break routine
iret ;Return to caller
kb_break endp
page
;****************************************************************************
; IBM_INT - Interrupt type 043H service routine.
; (IBM interrupt type 009H service routine)
; Hardware interrupt - 8041 interrupt
; This routine receives control whenever the 8041 signals an
; interrupt through the 8259 interrupt controller to the 8088.
; This service routine emulates all of the functions performed by
; the IBM PC keyboard interrupt (type 09). The data is read from
; the 8041, processed as needed, translated to ascii and extended
; codes, and placed in the keyboard queue. Touchscreen data is
; simply saved in a memory word.
;
; 1) Do if data byte from keyboard
; 1.1) Translate physical key address to key position
; 1.2) Do if not a keyboard shift key
; 1.2.1) Do if key pressed (not released)
; 1.2.1.1) Do if hold mode active
; 1.2.1.1.1) Reset hold mode
; 1.2.1.1.2) End of processing
; 1.2.1.2) Do if base mode
; 1.2.1.2.1) Do if stop key
; 1.2.1.2.1.1) Wait for another
; key press
; 1.2.1.2.1.2) End of processing
; 1.2.1.2.2) Do if break key
; 1.2.1.2.2.1) Reset keyboard q
; 1.2.1.2.2.2) Call user break
; routine
; 1.2.1.2.3) Translate key to ascii and
; extended codes and put in queue
; 1.2.1.3) Do if in extended char mode
; 1.2.1.3.1) Do if a numeric pad key
; 1.2.1.3.1.1) Add key value to
; input data value
; 1.2.1.3.1.1) End of processing
; 1.2.1.3.2) Translate key to ascii and
; extended codes and put in queue
; 1.2.1.4) Do if in control mode
; 1.2.1.4.1) Translate key to ascii and
; extended codes and put in queue
; 1.2.1.5) Do if in shift mode
; 1.2.1.5.1) Translate key to ascii and
; extended codes and put in queue
page
; 1.3) Do if a keyboard shift key
; 1.3.1) Do if the key was pressed (not released)
; 1.3.1.1) Do if not a toggle shift key
; 1.3.1.1.1) Set key pressed flag
; 1.3.1.2) Do if a toggle shift key
; 1.3.1.2.1) Do if in control mode
; 1.3.1.2.1.1) Translate key to
; ascii and extended
; codes and put in q
; 1.3.1.2.2) Do if key not already pressed
; 1.3.1.2.2.1) Set key pressed flg**
; 1.3.1.2.2.2) Toggle mode flag
; 1.3.2) Do if the key was released
; 1.3.2.1) Do if not a toggle shift key
; 1.3.2.1) Reset key pressed flag
; 1.3.2.2) Do if shift key is ext char
; 1.3.2.2.1) Do if input value
; is not zero
; 1.3.2.2.1.1) Put input
; value in keyboard q
; 1.3.2.2) Do if a toggle shift key
; 1.3.2.1) Reset key pressed flag
; 2) Do if data from touchscreen
; 2.1) Do if row report
; 2.1.1) Save row coordinate
; 2.2) Do if column report
; 2.2.1) Correct column coordinate (multiply by two)
; 2.2.2) Put row and column in touchscreen data word
; 2.3) Do if touchscreen release report
; 2.3.1) Set touchscreen data word to 0FFFFH
;
; Registers in:
; None.
; Registers out:
; None.
; Registers preserved:
; All.
;****************************************************************************
page
ibm_int label far ;External label for IBM keyboard
kb_int proc far ; interrupt service routine
push ax ;Save only what we absolutely must
push ds ; on the current stack
push cs ;Point ds to data segment
pop ds
mov old_ss,ss ;Save current stack pointer
mov old_sp,sp
mov ax,cs
mov ss,ax ;Switch to local stack
mov sp,new_sp
sub new_sp,STACK_LEN ;Record stack allocation
push old_ss ;Save everything we need to that
push old_sp ; wasn't saved before
push bx
push cx
push di
push es
sti ;Enable higher-priority interrupts
in al,KB_STAT ;Read 8041 status byte
test al,OBF_MASK ;If no data ready from 8041 then
jnz kb_int_005 ; don't do anything
jmp kb_int_900
kb_int_005 label near
cld ;Set string instrs to increment
mov ah,al ;Save 8041 status byte
in al,KB_DATA ;Read data byte from 8041
push ax
mov ah,ACK_CMND ;Acknowledge 8041 interrupt
call kb_cmnd_out
pop ax
test ah,TS_MASK ;If the data byte came from the
jz kb_int_010 ; touchscreen then go process it
jmp kb_int_200
page
;----------------------------------------------------------------------------
; 8041 data byte from keyboard
;----------------------------------------------------------------------------
kb_int_010 label near ;Data byte from keyboard
push ds ;Point es to data segment
pop es
mov ah,al ;Save keyboard data byte
and al,not KEY_RELEASE ;Mask off key released bit
mov bx,offset key_number ;Translate physical key address to
xlat ; key position number
mov di,offset kb_shift ;Use the table of keyboard shift
mov cx,KB_SHIFT_LEN ; keys to see if this key is a
repne scasb ; shift key
jne kb_int_015 ;If it is a shift key then go
jmp kb_int_100 ; process it
kb_int_015 label near ;Not a shift key, AH-pa AL-key no
test ah,KEY_RELEASE ;If the key was released then
jz kb_int_020 ; ignore it
jmp kb_int_900
kb_int_020 label near
test kb_flag_lsb,HOLD_MODE ;If we are in hold mode then
jz kb_int_030 ; end hold mode and ignore key
and kb_flag_lsb,not HOLD_MODE
jmp kb_int_900
kb_int_030 label near ;Process non-shift key
test kb_flag_msb,EXT_SHIFT ;If in extended character mode
jnz kb_int_040 ; go to ext char routine
test kb_flag_msb,CTRL_SHIFT ;If in control mode
jnz kb_int_050 ; go to control routine
test kb_flag_msb,LEFT_SHIFT or RIGHT_SHIFT ;If in shift mode
jnz kb_int_060 ; go to shift routine
jmp kb_int_035 ;Go to base mode routine
kb_int_035 label near ;Process non-shift key, base mode
cmp al,STOP_KEY ;If the key is the stop key
jnz kb_int_038 ; then suspend processing until
or kb_flag_lsb,HOLD_MODE ; another key is pressed
mov al,EOI_CMND ; (This is the CTRL-NumLock
out IC_CMND,al ; function on the IBM keyboard)
kb_int_037 label near
test kb_flag_lsb,HOLD_MODE
jnz kb_int_037
jmp kb_int_910
kb_int_038 label near ;else (not stop key)
cmp al,BREAK_KEY ; If the key is the break key
jnz kb_int_039 ; empty keyboard buffer
call kb_reset_q ; call user break routine
int BREAK_TYPE ; put zero keycode in queue
mov ax,00000H ; (IBM is CTRL-ScrollLock)
jmp kb_int_805 ; endif
kb_int_039 label near
mov cx,BASE_INDEX ; Put keycode in queue
jmp kb_int_800 ;endif
kb_int_040 label near ;Process non-shift key, extc mode
mov di,offset num_pad_keys
mov cx,NUM_PAD_LEN
repne scasb ;If the key is a numeric pad key
jne kb_int_045 ; then add the value to the
sub di,offset num_pad_keys+1 ; current input value
mov al,ext_data
mov ah,10
mul ah
add ax,di
mov ext_data,al
jmp kb_int_900
kb_int_045 label near ;else (not numeric pad key)
mov ext_data,0 ; clear input value
mov cx,EXTC_INDEX ; put keycode in queue
jmp kb_int_800 ;endif
kb_int_050 label near ;Process non-shift key, ctrl mode
mov cx,CTRL_INDEX ;Put keycode in queue
jmp kb_int_800
kb_int_060 label near ;Process non-shift key, shift mode
mov cx,SHIFT_INDEX ;Put keycode in queue
jmp kb_int_800
;Keyboard shift key, AH-physical addr AH-key number
; DI-pointer to shift key table entry
kb_int_100 label near
sub di,offset kb_shift+1 ;Load shift key flag byte mask
mov bl,kb_mask[di] ; in bl
test ah,KEY_RELEASE ;If the shift key was pressed
jnz kb_int_120
cmp bl,SCROLL_SHIFT ; If not a toggle shift key
jae kb_int_105
or kb_flag_msb,bl ; Set key pressed flag
jmp kb_int_900
kb_int_105 label near ; else (toggle shift key)
test kb_flag_msb,CTRL_SHIFT ; If in control mode
jz kb_int_110 ; go to non-shift key proc
jmp kb_int_015 ; endif
kb_int_110 label near
test bl,kb_flag_lsb ; If key already pressed
jz kb_int_115 ; ignore it
jmp kb_int_900 ; endif
kb_int_115 label near
or kb_flag_lsb,bl ; Set key pressed flag
xor kb_flag_msb,bl ; Toggle the mode flag
cmp al,INS_KEY ; If key is insert key
jnz kb_int_117 ; put keycode in queue
jmp kb_int_030 ; endif
kb_int_117 label near
jmp kb_int_900 ; endif
kb_int_120 label near ;else (shift key released)
cmp bl,SCROLL_SHIFT ; If not a toggle shift key
jae kb_int_135
not bl ; Reset key pressed flag
and kb_flag_msb,bl
cmp al,LEXT_KEY ; If an ext char key was
jz kb_int_125 ; released
cmp al,REXT_KEY
jz kb_int_125
jmp kb_int_900
kb_int_125 label near
mov al,ext_data ; If the input value is not
or al,al ; zero
jnz kb_int_130
jmp kb_int_900 ; zero save area
kb_int_130 label near ; put data value in
mov ext_data,0 ; keyboard queue
sub ah,ah ; endif
jmp kb_int_805 ; endif
kb_int_135 label near ; else (toggle shift key)
not bl ; Reset key pressed flag
and kb_flag_lsb,bl ; endif
jmp kb_int_900 ; endif
page
;----------------------------------------------------------------------------
; 8041 data byte from touchscreen
;----------------------------------------------------------------------------
kb_int_200 label near ;Touchscreen input
and ah,TS_MASK ;Isolate touchscreen flags
cmp ah,ROW_MASK ;If touch row report then
jz kb_int_205 ; go process it
cmp ah,COL_MASK ;If touch column report then
jz kb_int_210 ; go process it
cmp ah,REL_MASK ;If touchscreen release then
jz kb_int_215 ; go process it
jmp kb_int_900
kb_int_205 label near ;Touchscreen row report
mov ts_save,al ;Save touch row coordinate
jmp kb_int_900
;The 8041 reports touch column coordinates in the range 0-40. Therefore,
;the column coordinate must be multiplied by two to be in the range 0-80.
;NOTE - this means that a touch column coordinate will never be odd.
kb_int_210 label near ;Touchscreen column report
mov ah,0FFH ;Load row coordinate
xchg ts_save,ah
sal al,1 ;Correct column coordinate
mov ts_row_col,ax ;Store touch coordinates
jmp kb_int_900
kb_int_215 label near ;Touchscreen released
mov ax,0FFFFH ;Clear touch coordinates
xchg ts_row_col,ax
jmp kb_int_900
page
;----------------------------------------------------------------------------
; Translate key number to ascii and extended code depending on shift mode
; AL-HP ITF key position number, CX-Shift mode index value
;----------------------------------------------------------------------------
kb_int_800 label near
les bx,kb_kc_table ;Load pointer to keycode translate
add bx,cx ; table and index into table
sub ah,ah ; using key number and shift
mov cl,3 ; mode.
sal ax,cl
add bx,ax ;Load keycode table entry giving
mov ax,es:[bx] ; AH-Extended code, AL-Ascii code
cmp ah,0FFH ;Ignore any non-mapped keys
jz kb_int_900
cmp al,0FFH
jz kb_int_900
;----------------------------------------------------------------------------
; Put keycode (ascii code plus extended code) in keyboard queue
; AH-extended code, AL-ascii code
;----------------------------------------------------------------------------
kb_int_805 label near
test kb_flag_msb,CAPS_MODE ;If in caps lock mode then
jz kb_int_815
test kb_flag_msb,LEFT_SHIFT or RIGHT_SHIFT
jnz kb_int_810 ; If not in shift mode then
cmp al,'a'
jb kb_int_815
cmp al,'z' ; If lowercase ascii alpha
ja kb_int_815 ; convert to uppercase
and al,11011111B ; endif
jmp kb_int_815 ;
kb_int_810 label near ; else
cmp al,'A' ; If uppercase ascii alpha
jb kb_int_815 ; convert to lowercase
cmp al,'Z' ; endif
ja kb_int_815 ; endif
or al,00100000B ;endif
kb_int_815 label near
call kb_write_q ;Add keycode to keyboard queue
jnz kb_int_900 ;Make noise if queue is full
mov ah,TONE_0_CMND
call kb_cmnd_out
jmp kb_int_900
page
kb_int_900 label near ;End of keyboard interrupt service
cli ;Disable external interrupts
mov al,EOI_CMND ;Send End of Interrupt command to
out IC_CMND,al ; 8259 interrupt controller
kb_int_910 label near ;End of keyboard intr, no EOI
cli ;Disable external interrupts
pop es ;Restore saved values
pop di
pop cx
pop bx
pop old_sp
pop old_ss
mov ss,old_ss ;Restore interrupted routines's
mov sp,old_sp ; stack pointer
add new_sp,STACK_LEN ;Release allocated stack space
sti
pop ds ;Restore saved registers
pop ax
iret ;Return from interrupt
kb_int endp
;****************************************************************************
;****************************************************************************
;
; KEYBOARD DRIVER TRANSLATE TABLES
;
;
; This module contains the translate tables used by the keyboard driver.
; key_number - Key physical address to key number translate table
; ibm_table - Key number to IBM PC keycode translate table
;****************************************************************************
;****************************************************************************
;****************************************************************************
; KEY_NUMBER - Key physical address to key number translate table
; This table translates the physical address for a key that is
; reported by the 8041 to the key's position number on the ITF
; keyboard.
;
; The physical key address reported by the 8041 is a 7-bit value -
; the eighth bit is used to indicate whether the key went up or
; down. Therefore, there are only 128 possible entries in this
; table. The physical key address is used to index this table and
; the resulting value is the corresponding ITF key number.
; A value of zero indicates no key corresponds to the physical addr.
;****************************************************************************
key_number label word
; ITF keyboard key position Physical
; (000 = No key) address
db 000,000,000,000,000,000,000,000 ;000-007
db 007,014,013,012,011,010,009,008 ;008-00F
db 023,030,029,028,027,026,025,024 ;010-017
db 039,046,045,044,043,042,041,040 ;018-01F
db 055,062,061,060,059,058,057,056 ;020-027
db 071,078,077,076,016,074,073,072 ;028-02F
db 000,085,084,083,000,082,080,081 ;030-037
db 006,053,002,048,015,003,004,005 ;038-03F
db 022,064,075,047,018,019,020,021 ;040-047
db 038,031,032,033,034,035,036,037 ;048-04F
db 054,017,000,049,050,051,052,001 ;050-057
db 101,097,100,096,099,095,098,094 ;058-05F
db 107,093,104,092,103,091,102,090 ;060-067
db 000,089,106,088,000,087,105,086 ;068-06F
db 070,063,079,065,066,067,068,069 ;070-077
db 000,000,000,000,000,000,000,000 ;078-07F
page
;****************************************************************************
; IBM_TABLE - Key number to IBM PC keycode translate table
; This table translates a key number and shift mode to an IBM PC
; keycode.
;
; The key number is multiplied by six and the result is used to
; index the table. Each table entry is made up of four two-byte
; keycodes corresponding to base, shift, ctrl, and extc shift modes
; respectively. The shift mode is used to index the table entry and
; the resulting two-byte value is the IBM PC keycode.
;
; The IBM PC keycode is a one word value made up of two single byte
; codes. The MSB contains the IBM extended character code and the
; LSB contains the IBM ascii code for the key.
;****************************************************************************
ibm_table label word
; Ext HP
; Base Shift Ctrl Char Key #
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;000 - dummy key entry
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;001
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;002
dw 03B00H, 05400H, 05E00H, 06800H ;003
dw 03C00H, 05500H, 05F00H, 06900H ;004
dw 03D00H, 05600H, 06000H, 06A00H ;005
dw 03E00H, 05700H, 06100H, 06B00H ;006
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;007
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;008
dw 03F00H, 05800H, 06200H, 06C00H ;009
dw 04000H, 05900H, 06300H, 06D00H ;010
dw 04100H, 05A00H, 06400H, 06E00H ;011
dw 04200H, 05B00H, 06500H, 06F00H ;012
dw 07500H, 07500H, 0FFFFH, 0FFFFH ;013
dw 07700H, 07700H, 0FFFFH, 0FFFFH ;014
dw 02960H, 0297EH, 0FFFFH, 0FFFFH ;015
dw 00231H, 00221H, 0FFFFH, 07800H ;016
dw 00332H, 00340H, 00000H, 07900H ;017
dw 00433H, 00423H, 0FFFFH, 07A00H ;018
dw 00534H, 00524H, 0FFFFH, 07B00H ;019
dw 00635H, 00625H, 0FFFFH, 07C00H ;020
dw 00736H, 0075EH, 0071EH, 07D00H ;021
dw 00837H, 00826H, 0FFFFH, 07E00H ;022
dw 00938H, 0092AH, 0FFFFH, 07F00H ;023
dw 00A39H, 00A28H, 0FFFFH, 08000H ;024
dw 00B30H, 00B29H, 0FFFFH, 08100H ;025
dw 00C2DH, 00C5FH, 00C1FH, 08200H ;026
dw 00D3DH, 00D2BH, 0FFFFH, 08300H ;027
dw 00E08H, 00E08H, 00E7FH, 0FFFFH ;028
dw 05200H, 05200H, 0FFFFH, 0FFFFH ;029
dw 05300H, 05300H, 0FFFFH, 0FFFFH ;030
dw 00F09H, 00F00H, 0FFFFH, 0FFFFH ;031
dw 01071H, 01051H, 01011H, 01000H ;032
dw 01177H, 01157H, 01117H, 01100H ;033
dw 01265H, 01245H, 01205H, 01200H ;034
dw 01372H, 01352H, 01312H, 01300H ;035
dw 01474H, 01454H, 01414H, 01400H ;036
dw 01579H, 01559H, 01519H, 01500H ;037
dw 01675H, 01655H, 01615H, 01600H ;038
dw 01769H, 01749H, 01709H, 01700H ;039
dw 0186FH, 0184FH, 0180FH, 01800H ;040
dw 01970H, 01950H, 01910H, 01900H ;041
dw 01A5BH, 01A7BH, 01A1BH, 0FFFFH ;042
dw 01B5DH, 01B7DH, 01B1DH, 0FFFFH ;043
dw 02B5CH, 02B7CH, 02B1CH, 0FFFFH ;044
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;045
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;046
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;047
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;048
dw 01E61H, 01E41H, 01E01H, 01E00H ;049
dw 01F73H, 01F53H, 01F13H, 01F00H ;050
dw 02064H, 02044H, 02004H, 02000H ;051
dw 02166H, 02146H, 02106H, 02100H ;052
dw 02267H, 02247H, 02207H, 02200H ;053
dw 02368H, 02348H, 02308H, 02300H ;054
dw 0246AH, 0244AH, 0240AH, 02400H ;055
dw 0256BH, 0254BH, 0250BH, 02500H ;056
dw 0266CH, 0264CH, 0260CH, 02600H ;057
dw 0273BH, 0273AH, 0FFFFH, 0FFFFH ;058
dw 02827H, 02822H, 0FFFFH, 0FFFFH ;059
dw 01C0DH, 01C0DH, 01C0AH, 0FFFFH ;060
dw 04700H, 04700H, 0FFFFH, 0FFFFH ;061
dw 04900H, 04900H, 08400H, 0FFFFH ;062
dw 0011BH, 0011BH, 0011BH, 0FFFFH ;063
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;064
dw 02C7AH, 02C5AH, 02C1AH, 02C00H ;065
dw 02D78H, 02D58H, 02D18H, 02D00H ;066
dw 02E63H, 02E43H, 02E03H, 02E00H ;067
dw 02F76H, 02F56H, 02F16H, 02F00H ;068
dw 03062H, 03042H, 03002H, 03000H ;069
dw 0316EH, 0314EH, 0310EH, 03100H ;070
dw 0326DH, 0324DH, 0320DH, 03200H ;071
dw 0332CH, 0333CH, 0FFFFH, 0FFFFH ;072
dw 0342EH, 0343EH, 0FFFFH, 0FFFFH ;073
dw 0352FH, 0353FH, 0FFFFH, 0FFFFH ;074
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;075
dw 04F00H, 04F00H, 0FFFFH, 0FFFFH ;076
dw 04800H, 04800H, 0FFFFH, 0FFFFH ;077
dw 05100H, 05100H, 07600H, 0FFFFH ;078
dw 0FFFFH, 0FFFFH, 07200H, 0FFFFH ;079
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;080
dw 03920H, 03920H, 03920H, 03920H ;081
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;082
dw 04B00H, 04B00H, 07300H, 0FFFFH ;083
dw 05000H, 05000H, 0FFFFH, 0FFFFH ;084
dw 04D00H, 04D00H, 07400H, 0FFFFH ;085
dw 04300H, 05C00H, 06600H, 07000H ;086
dw 04400H, 05D00H, 06700H, 07100H ;087
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;088
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;089
dw 0372AH, 0372AH, 0FFFFH, 0FFFFH ;090
dw 0352FH, 0352FH, 0FFFFH, 0FFFFH ;091
dw 04E2BH, 04E2BH, 0FFFFH, 0FFFFH ;092
dw 04A2DH, 04A2DH, 0FFFFH, 0FFFFH ;093
dw 04737H, 04737H, 0FFFFH, 0FFFFH ;094
dw 04838H, 04838H, 0FFFFH, 0FFFFH ;095
dw 04939H, 04939H, 0FFFFH, 0FFFFH ;096
dw 0FFFFH, 0FFFFH, 0FFFFH, 0FFFFH ;097
dw 04B34H, 04B34H, 0FFFFH, 0FFFFH ;098
dw 04C35H, 04C35H, 0FFFFH, 0FFFFH ;099
dw 04D36H, 04D36H, 0FFFFH, 0FFFFH ;100
dw 0332CH, 0332CH, 0FFFFH, 0FFFFH ;101
dw 04F31H, 04F31H, 0FFFFH, 0FFFFH ;102
dw 05032H, 05032H, 0FFFFH, 0FFFFH ;103
dw 05133H, 05133H, 0FFFFH, 0FFFFH ;104
dw 05230H, 05230H, 0FFFFH, 0FFFFH ;105
dw 0342EH, 0342EH, 0FFFFH, 0FFFFH ;106
dw 00F09H, 00F00H, 0FFFFH, 0FFFFH ;107
pccode ends
end